﻿' <summary>
' BeeWit IDE Entorno de desarrollo Visual para php.
' BeeWitPHP IDE es el único entorno de desarrollo para PHP 
' de tipo WYSIWYG (What You See Is What You Get). 
' ¡Ahora si!, aproveche la potencia del lenguaje PHP 
' y desarrolle más rápidamente gracias a la programación 
' intuitiva de BeeWit.
' Copyright © 2010 Dewins Murillo Garcia 
' EMAIL: dewinsmg@gmail.com
' EMAIL: dewins@beewitsoft.com
' Este Programa es Software Libre: usted puede redistribuirlo 
' y/o modificarlo bajo los términos de la Licencia Publica General 
' GNU como es publicada por la Fundacion de Software Libre; 
' en la 3ra versión de la licencia.
' Este programa es distribuido con la esperanza de que sea útil, 
' pero SIN GARANTÍA ALGUNA; sin siquiera la garantía implícita 
' de VALOR COMERCIAL o FORMADO PARA UN PROPÓSITO EN PARTICULAR. 
' Vea la Licencia Publica General GNU para mas detalles.
' Usted debe haber recibido una copia de la Licencia Publica General 
' GNU junto con este programa. Si no, vaya a http://www.beewitsoft.com
' o en http://code.google.com/p/ajax-beewit-php-ide/
' </summary>
' <remarks></remarks>

Imports ICSharpCode.TextEditor
Imports ICSharpCode.TextEditor.Document
Imports xdc.XDebug
Imports xdc.GUI
Imports xdc.GUI.FileLoader

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Imports System.Diagnostics
Imports System.IO

Public Class clsDebug

    Private WithEvents _client As xdc.XDebug.Client
    Private _CurrentLocation As xdc.XDebug.Location
    Private BreakPoints() As xdc.XDebug.Breakpoint
    Private _IsRunning As Boolean = False
    Private proceso As New System.Diagnostics.Process
    Private XDebugCounter As Long

    ReadOnly Property IsRunning()
        Get
            Return _IsRunning
        End Get
    End Property

    Public Sub New()
        General.Settings = New clsSettings
        Dim XDebugPort As Long = General.Settings.GetTagValue("xdebug_port")
        _client = New xdc.XDebug.Client("localhost", XDebugPort)
        _CurrentLocation = New xdc.XDebug.Location
        _CurrentLocation.line = -1
    End Sub

    Private Function _client_onEventCallback(ByVal e As xdc.XDebug.XDebugEventArgs) As Boolean Handles _client.EventCallback
        Try
            'XDebugCounter += 1
            'If _client.State = XdebugClientState.Break And e.CurrentLocation.filename Is Nothing Then
            '    XDebugCounter = XDebugCounter
            'End If
            'Control_Console.AddMessages(" ***** [XDebugCounter=" & XDebugCounter & "] (" & e.EventType.ToString & ").", ctlConsole.enumTypeMessages.isNOTIFICATION)
            If General.Control_Menu.StopDebuggingToolStripMenuItem.Enabled = True Then
                General.Control_Debug.lstStates.Items.Add(_client.State.ToString)
                General.Control_Debug.lstStates.SelectedIndex = General.Control_Debug.lstStates.Items.Count - 1
            End If
            Select Case e.EventType
                Case xdc.XDebug.XDebugEventType.DebuggerConnected
                    Me.OnXdebuggerConnected(e)
                    Exit Select

                Case xdc.XDebug.XDebugEventType.ConnectionInitialized
                    Return OnXdebugConnectionInitialized(e)

                Case xdc.XDebug.XDebugEventType.MessageReceived
                    Me.OnXdebugMessageReceived(e)
                    Exit Select

                Case xdc.XDebug.XDebugEventType.CommandSent
                    Me.OnXdebugCommandSent(e)
                    Exit Select

                Case xdc.XDebug.XDebugEventType.BreakpointHit
                    Me.OnXdebugBreakpointHit(e)
                    Exit Select

                Case xdc.XDebug.XDebugEventType.ErrorOccured
                    Me.OnXdebugErrorOccurred(e)
                    Exit Select

                Case xdc.XDebug.XDebugEventType.ScriptFinished
                    Me.OnXdebugScriptFinished(e)
                    Exit Select
                Case Else
                    Control_Console.AddMessages("(EVENTO DESCONOCIDO : " & e.EventType.ToString & ").", ctlConsole.enumTypeMessages.isNOTIFICATION)
                    Exit Select
            End Select
        Catch ex As Exception
            Control_Console.AddMessages(ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
        End Try
    End Function

    Private Sub OnXdebuggerConnected(ByVal e As xdc.XDebug.XDebugEventArgs)
        Control_Console.AddMessages("(-) Debugger connected." & e.EventType.ToString & ").", ctlConsole.enumTypeMessages.isNOTIFICATION)
        Try
            If _client.Initialize() Then
                Control_Console.AddMessages("(-) XDebugClient initialized.", ctlConsole.enumTypeMessages.isNOTIFICATION)
                SendContinuationCommand("run")
            Else
                Return
            End If
        Catch ex As Exception
            Control_Console.AddMessages("(-) Cannot initialize XDebugClient: " + ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
            Control_Console.AddMessages("XDebugClient was unable to initialize. Debugging session terminated." & vbCr & vbLf & vbCr & vbLf + ex.Message + ". System error", ctlConsole.enumTypeMessages.isCRITICAL)
            StopDebugging()
        End Try
    End Sub

    Private Function OnXdebugConnectionInitialized(ByVal e As xdc.XDebug.XDebugEventArgs) As Boolean
        Return True
    End Function

    Private Sub OnXdebugCommandSent(ByVal e As xdc.XDebug.XDebugEventArgs)
        Control_Console.AddMessages(" -> SENT: " & Convert.ToString(e.Message.RawMessage), ctlConsole.enumTypeMessages.isNOTIFICATION)
    End Sub

    Private Sub OnXdebugBreakpointHit(ByVal e As xdc.XDebug.XDebugEventArgs)
        Try
            Dim FileName As String = e.CurrentLocation.filename
            Dim NodeFound As clsNode = Control_Explorer.SearchClassbyFileName(e.CurrentLocation.filename)

            If Not NodeFound Is Nothing Then
                Control_Main.AddEditor(e.CurrentLocation.filename, NodeFound)
                Control_Console.AddMessages("Opened! " & NodeFound.ToolTipText & ". ", ctlConsole.enumTypeMessages.isINFORMATION)
            End If

            Me.SetActiveFileAndLine(e.CurrentLocation)
            General.Control_Debug.setCallstack(_client)

            If Not e.CurrentLocation.filename Is Nothing Then
                If e.CurrentLocation.filename.ToUpper.Trim Like "*INDEX.PHP*" Then
                    If e.CurrentLocation.line = 1 Then
                        SendContinuationCommand("run")
                        Exit Sub
                    End If
                End If
            End If
            Try
                Call General.MainForm.Activate()
                General.MainForm.Focus()
            Catch ex As Exception

            End Try
        Catch ex As Exception
            Control_Console.AddMessages(ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
        End Try
    End Sub

    Public Sub InspectSelection()
    	Dim VarName As String = General.Control_Main.ActualEditor.ActualSelectionWord
    	VarName=trim(VarName)
        Dim dProperty As xdc.XDebug.Property = _client.GetPropertyValue(VarName, 0)
        If dProperty Is Nothing Then
            dProperty = New xdc.XDebug.Property(VarName, "not accesible", xdc.XDebug.PropertyType.Scalar, True, VarName)
        End If

        If Not dProperty Is Nothing Then
            General.Control_Debug.LoadProperty(_client, dProperty, Nothing)
        End If
    End Sub

    Private Sub SetActiveFileAndLine(ByVal ActualLocation As xdc.XDebug.Location)
        RemoveActiveMarks()
        For i = 0 To General.Control_Main.tabContainer.Items.Count - 1
            If General.Control_Main.tabContainer.Items(i).ToString = "BeeWit.ctlEditor" Then
                Dim Editor As ctlEditor = General.Control_Main.tabContainer.Items(i)
                If Editor.Path.ToUpper = ActualLocation.filename.ToUpper Then
                    Editor.SetActiveFileAndLine(ActualLocation.line)
                End If
            End If
        Next
    End Sub

    Private Sub OnXdebugErrorOccurred(ByVal e As xdc.XDebug.XDebugEventArgs)
        If e.ErrorType = xdc.XDebug.XDebugErrorType.Warning Then
            Control_Console.AddMessages("(!) PHP Notice: " & Convert.ToString(e.ErrorMessage), ctlConsole.enumTypeMessages.isEXCLAMATION)
            Me._client.Run()
        Else
            Control_Console.AddMessages("(!) PHP Fatal error: " & Convert.ToString(e.ErrorMessage), ctlConsole.enumTypeMessages.isCRITICAL)
            Control_Console.AddMessages("A Fatal error occurred:" & vbCr & vbLf & vbCr & vbLf & Convert.ToString(e.ErrorMessage) & vbCr & vbLf & vbCr & vbLf & "Your script has been terminated.", ctlConsole.enumTypeMessages.isCRITICAL)
            StopDebugging()
        End If
    End Sub

    Private Sub OnXdebugScriptFinished(ByVal e As xdc.XDebug.XDebugEventArgs)
        Control_Console.AddMessages("(!) Script finished.", ctlConsole.enumTypeMessages.isCRITICAL)
        StopDebugging()
    End Sub

    Private Sub OnXdebugMessageReceived(ByVal e As xdc.XDebug.XDebugEventArgs)
        ' Nothing to do for now
    End Sub

    'Dim Data As String = e.Message.RawMessage.ToString
    'If Data Like "*status=""stopping""*" Then
    '    Dim OK As Boolean = True
    '    _client.Run()
    'End If

    Public Sub StopDebugging()
        Control_Console.AddMessages("(-) Stopping and disconnecting.", ctlConsole.enumTypeMessages.isNOTIFICATION)
        _client.Disconnect()
        RemoveActiveMarks()
        General.Control_Menu.StopDebuggingToolStripMenuItem.Enabled = False
        MenuRunning(False)
        Control_Console.AddMessages("(!) Debugging session terminated.", ctlConsole.enumTypeMessages.isNOTIFICATION)
    End Sub

    Private Sub MenuRunning(ByVal State As Boolean)
        General.Control_Menu.StepIntoToolStripMenuItem.Enabled = State
        General.Control_Menu.StepOutToolStripMenuItem.Enabled = State
        General.Control_Menu.StepOverToolStripMenuItem.Enabled = State
        General.Control_Menu.StopDebuggingToolStripMenuItem.Enabled = State

        General.Control_Menu.InspectToolStripMenuItem.Enabled = State
        General.Control_Menu.btnStop.Enabled = State
        General.Control_Menu.btnInspect.Enabled = State
        
        _IsRunning = State
    End Sub

    Private Sub RemoveActiveMarks()
        For i = 0 To General.Control_Main.tabContainer.Items.Count - 1
            If General.Control_Main.tabContainer.Items(i).ToString = "BeeWit.ctlEditor" Then
                Dim Editor As ctlEditor = General.Control_Main.tabContainer.Items(i)
                Editor.RemoveActiveMarks()
            End If
        Next
    End Sub

    Public Sub listenForConnection()
        Control_Console.AddMessages("(-) Waiting for xdebug to connect", ctlConsole.enumTypeMessages.isNOTIFICATION)
        Try
            Dim apachePort As Long = General.Settings.GetTagValue("apache_web_server_port")
            _client.listenForConnection()
            MenuRunning(True)
            proceso.StartInfo.FileName = "http://localhost:" & apachePort & "/" & General.Project_Name & "/index.php?XDEBUG_SESSION_START=1" ''.StartInfo.FileName = "http://localhost:8090/" & General.Project_Name & "/index.php?XDEBUG_SESSION_START=1"
            proceso.EnableRaisingEvents = True
            AddHandler proceso.Exited, AddressOf Me.WebBrowserClosed
            proceso.Start()
            Control_Console.AddMessages("listen For Connection: " + proceso.StartInfo.FileName, ctlConsole.enumTypeMessages.isINFORMATION)
        Catch ex As Exception
            Control_Console.AddMessages("Unable to create listening socket: " + ex.Message + ". Cannot open socket", ctlConsole.enumTypeMessages.isNOTIFICATION)
        End Try
    End Sub

    Private Sub WebBrowserClosed()
        Dim i As Long = 0
    End Sub

    Public Sub Run()
        Try
            SendContinuationCommand("run")
        Catch ex As Exception
            Control_Console.AddMessages("Run: " + ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
        End Try
    End Sub

    Private Sub SendContinuationCommand(ByVal command As String)
        Try
            AddBreakPointers()
        Catch ex As Exception
            Control_Console.AddMessages("Send Continuation Command AddBreakPointers: " + ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
        End Try
        Try
            _client.Run(command)
        Catch ex As Exception
            If ex.Message.ToUpper Like "*STOPPING*" Then
                RemoveActiveMarks()
                _client.Disconnect()
                _client.listenForConnection()
            Else
                Control_Console.AddMessages("Send Continuation Command Run: " + ex.Message, ctlConsole.enumTypeMessages.isCRITICAL)
            End If
        End Try
    End Sub

    Private Sub AddBreakPointers()
        If Not _client.State = XdebugClientState.Break Then
            If Not BreakPoints Is Nothing Then
                For iBreak = 0 To BreakPoints.Length - 1
                    _client.RemoveBreakpoint(BreakPoints(iBreak))
                Next
            End If
        End If

        BreakPoints = Nothing
        For i = 0 To General.Control_Main.tabContainer.Items.Count - 1
            If General.Control_Main.tabContainer.Items(i).ToString = "BeeWit.ctlEditor" Then
                Dim Editor As ctlEditor = General.Control_Main.tabContainer.Items(i)
                Dim tmpBreakPoints() As xdc.XDebug.Breakpoint = Editor.GetBreakPoints()
                If Not tmpBreakPoints Is Nothing Then
                    For iBreak = 0 To tmpBreakPoints.Length - 1
                        If BreakPoints Is Nothing Then
                            ReDim BreakPoints(0)
                        Else
                            ReDim Preserve BreakPoints(BreakPoints.Length)
                        End If
                        BreakPoints(BreakPoints.Length - 1) = tmpBreakPoints(iBreak)
                    Next
                End If
            End If
        Next
        If Not _client.State = XdebugClientState.Break Then
            If Not BreakPoints Is Nothing Then
                For iBreak = 0 To BreakPoints.Length - 1
                    _client.AddBreakpoint(BreakPoints(iBreak))
                Next
            End If
        End If
    End Sub

    Public Sub StepOver()
        If _client.State = XdebugClientState.Break Then
            SendContinuationCommand("step_over")
        End If
    End Sub

    Public Sub StepInto()
        If _client.State = XdebugClientState.Break Then
            SendContinuationCommand("step_into")
        End If
    End Sub

    Public Sub StepOut()
        If _client.State = XdebugClientState.Break Then
            SendContinuationCommand("step_out")
        End If
    End Sub

End Class
